/**
* @file Main.cpp
*
* Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. All rights reserved.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/

#include <iostream>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <cstring>
#include <csignal>
#include <ctime>

#include "gpio.h"
int gpio_export_open(int pin);
// the function of read wave
void read_wave(union sigval v);
void init_time_collect();
// the function of pwm
void output_pwm(union sigval v);
void init_time_pwm();
// the var of read wave
int val=0;
int val_old=0;
int rising_edge_times=0;
int detect_times=0;
int collect_complete=0;
// the var of pwm
int count=0;
int pwm=0;
// frequent
int f=0;
using namespace std;

namespace{
    gpio io_ctrl;
}

int main(int argc, char* argv[])
{
    int val;
    gpio_export_open(0);
    gpio_export_open(1);
    io_ctrl.gpio_set_direction(0,0);

    io_ctrl.gpio_get_value(0,&val);
    io_ctrl.gpio_set_direction(4,1);
    io_ctrl.gpio_set_direction(3,1);
    io_ctrl.gpio_set_value(4,0);
    //io_ctrl.gpio_set_value(3,0);
    init_time_pwm();
    init_time_collect();
    int uk=0;
    int uk_1=0;
    int delta_uk=0;
    int yk=0;
    int rk=0;
    float q0=1;
    float q1=-0.3;
    float q2=0.1;
    int ek=0;
    int ek_1=0;
    int ek_2=0;
    char rk_string[3]={};
    rk=17;
    INFO_LOG("test gpio start\n");
    while(1) {
        int fd_rk = open("/home/HwHiAiUser/rk", 00);
        if (-1 == fd_rk) {
            ERROR_LOG("open failed");
        } else {
          if (-1 == read(fd_rk, rk_string, 2)) {
            ERROR_LOG("gpio open failed");
            close(fd_rk);
          }else{
              rk=atoi(rk_string);
              close(fd_rk);
          }
        }
        while(!collect_complete);

        yk=f;
        ek=(rk-yk)*1000;
        cout << "rk " <<  rk << " yk "<< yk <<endl;
        delta_uk=q0*ek+q1*ek_1+q2*ek_2;
        uk=uk_1+delta_uk;
        if(uk<0)
            uk = 0;
        else if(uk>100*1000)
            uk = 100*1000;
        //cout << "uk " << uk << " uk-1 " <<uk_1 << " delta_uk "<< delta_uk <<endl;
        pwm=uk/1000;
        uk_1=uk;
        ek_2=ek_1;
        ek_1=ek;
        collect_complete=0;  // this sampling has been used
    }
    INFO_LOG("test gpio end\n");

}
/** open gpio 0 or 1*/
int gpio_export_open(int pin)
{
    int fd_export = open("/sys/class/gpio/export", 01);
    if (-1 == fd_export) {
        ERROR_LOG("open failed");
        return -1;
    }
    switch(pin) {
        case 0:
            if(-1 == write(fd_export, "504", sizeof("504")))
            {
                ERROR_LOG("gpio open failed");
                close(fd_export);
                return -2;
            }
            break;
        case 1:
            if(-1 == write(fd_export, "444", sizeof("444")))
            {
                ERROR_LOG("gpio open failed");
                close(fd_export);
                return -2;
            }
            break;
        default:
            ERROR_LOG("gpio %d not exist.", pin);
            close(fd_export);
            return -3;
    }
    close(fd_export);
    return 0;
}

//---------------read wave-----------------
/**detect rising edge*/
void read_wave(union sigval v){
    detect_times++;
    // read the gpio0
    io_ctrl.gpio_get_value(0,&val);
    // rising edge detected
    if(1==val && 0==val_old) {
        //cout<<"tg"<<endl;
        rising_edge_times++;
    }
    val_old=val;
    //count<< detect_times;
    // caculate rate
    if(200 <= detect_times) { // 1000ms
        //cout << rising_edge_times*2.5 <<endl;
        collect_complete=1;
        f=rising_edge_times;
        detect_times=0;
        rising_edge_times=0;
    } else {
        collect_complete=0;
    }
}

void init_time_collect() {
    timer_t timerid;
    struct sigevent evp;
    memset(&evp, 0, sizeof(struct sigevent));
    evp.sigev_value.sival_int = 222;
    evp.sigev_notify = SIGEV_THREAD;
    evp.sigev_notify_function = read_wave;
    if (timer_create(CLOCK_REALTIME, &evp, &timerid) == -1)
    {
        perror("fail to timer_create");
        exit(-1);
    }
    struct itimerspec it;
    it.it_interval.tv_sec = 0; // interval
    it.it_interval.tv_nsec = 2000*1000;
    it.it_value.tv_sec = 3;  // first time count down
    it.it_value.tv_nsec = 0;
    if (timer_settime(timerid, 0, &it, NULL) == -1)
    {
        perror("fail to timer_settime");
        exit(-1);
    }
}
//---------------read wave end end end end end

//---------------output pwm--------------------

void output_pwm(union sigval v) {
    count++;
    if (0 >= pwm) {
        io_ctrl.gpio_set_value(3,0);
    } else if (count == 1) {
        io_ctrl.gpio_set_value(3,1);
    } else if(count == pwm) {
        //cout << pwm << endl;
        io_ctrl.gpio_set_value(3,0);
    }

    if (count >= 100) {
        count = 0;
        //static time_t start,stop;
        //stop = clock();
        //cout << (float)(stop-start)/CLOCKS_PER_SEC << "time" <<endl;
        //start = clock();
    }

}





void init_time_pwm() {
    timer_t timerid;
    struct sigevent evp;
    memset(&evp, 0, sizeof(struct sigevent));
    evp.sigev_value.sival_int = 111;
    evp.sigev_notify = SIGEV_THREAD;
    evp.sigev_notify_function = output_pwm;
    if (timer_create(CLOCK_REALTIME, &evp, &timerid) == -1)
    {
        perror("fail to timer_create");
        exit(-1);
    }
    struct itimerspec it;
    it.it_interval.tv_sec = 0; // interval
    it.it_interval.tv_nsec = 500*1000;
    it.it_value.tv_sec = 3;  // first time count down
    it.it_value.tv_nsec = 0;
    if (timer_settime(timerid, 0, &it, NULL) == -1)
    {
        perror("fail to timer_settime");
        exit(-1);
    }
}

//---------------output pwm end end end end end end
